<?php

declare(strict_types=1);

namespace App\Command;

use App\Core\DB;
use Hyperf\Command\Annotation\Command;
use Hyperf\Command\Command as HyperfCommand;
use Hyperf\Database\Schema\Schema;
use Hyperf\Utils\Str;

#[Command]
class TableEntity extends HyperfCommand
{

    protected $name = 'entity';


    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $tables = DB::select('show table status');
        if( ! (bool)$tables){
            echo '未查询到数据库';
            exit;
        }

        foreach ($tables as $table){
            $table = (array)$table;
            $this->createEntityFile($table);
        }
    }

    /**
     * 生成实体类
     * @param   string $table
     * @param   string $path
     * @return  array
     */
    public function createEntityFile($table)
    {
        $path = dirname(__DIR__).'/Model/';
        $tableName = $table['Name'];

        $content = "<?php \r\n\r\n";

        $content .= "namespace App\Model\Entity;\r\n\r\n";
        $content .= "use App\Core\Model;\r\n\r\n";

        $oldTableName = $tableName;
        if (strpos($tableName, '_') > 0) {
            $tA = explode('_', $tableName);
            foreach ($tA as $kk => $v) {
                $tA[$kk] = ucfirst($v);
            }
            $tableName = implode('', $tA);
        } else {
            $tableName = ucfirst($tableName);
        }

        $file = rtrim($path, '/').'/Entity/'.ucfirst($tableName).'Entity.php';
        $tableClassName = $tableName. 'Entity';
        $content .= "/**\r\n";
        $content .= " * ".$table['Comment']."\r\n";

        $sql = "select * from information_schema.COLUMNS
                    where table_name = '$oldTableName' and TABLE_SCHEMA = '".env('DB_DATABASE').'\'';

        $tColumns = Schema::getColumnListing($oldTableName);
        $tColumns = (array)$tColumns;
        $columns = (array)DB::select($sql);

        foreach ($columns as $column){

            $column = (array)$column;
            if( ! in_array($column['COLUMN_NAME'], $tColumns)){
                continue;
            }

            $name = $column['COLUMN_NAME'];
            $typeName = 'string';
            if ($column['DATA_TYPE'] == 'int') {
                $typeName = 'int';
            } elseif ($column['DATA_TYPE'] == 'decimal') {
                $typeName = 'float';
            }

            switch ($column['DATA_TYPE']) {
                case 'int':
                case 'bigint':
                case 'mediumint':
                case 'smallint':
                case 'integer':
                case 'tinyint':
                    $typeName = 'int';
                    break;

                case 'double':
                case 'decimal':
                    $typeName = 'float';
                    break;
                case 'date':
                case 'datetime':
                    $typeName = 'datetime';
                    break;
                default:
                    $typeName = 'string';
                    break;
            }


            $comment = $column['COLUMN_COMMENT'];
            $content .= " * @property $typeName $".Str::camel($name)." $comment\r\n";
        }

        $content .= " */\r\n";
        $content .= "abstract class " . $tableClassName . " extends Model\r\n{\r\n";

        $content .= "    /**\r\n";
        $content .= "     * 表名\r\n";
        $content .= "     * @var string\r\n";
        $content .= "     */\r\n";
        $content .= '    const TABLE = \''.$oldTableName."';\r\n\r\n";
        $content .= '    const TABLE_NAME = \''.$table['Comment']."';\r\n\r\n";

        foreach ($columns as $column){
            $column = (array)$column;
            if( ! in_array($column['COLUMN_NAME'], $tColumns)) continue;
            $content .= "    /**\r\n";
            $content .= "     * " . $column['COLUMN_COMMENT'] . "\r\n";
            $content .= "     * @var string\r\n";
            $content .= "     */\r\n";
            $content .= '    const C_' . strtoupper($column['COLUMN_NAME']) . ' = \'' . $column['COLUMN_NAME'] . "';\r\n\r\n";
            $allClomun[] = '\''.$column['COLUMN_NAME'].'\'';
        }

        $content .= "    /**\r\n";
        $content .= "     * 字段名称\r\n";
        $content .= "     * @var array \r\n";
        $content .= "     */\r\n";
        $content .= '    const COLUMN = [';
        foreach ($columns as $column){
            $column = (array)$column;
            if( ! in_array($column['COLUMN_NAME'], $tColumns)) continue;
            $typeName = '';
            $strLength = $column['CHARACTER_MAXIMUM_LENGTH'];
            switch ($column['DATA_TYPE']) {
                case 'tinyint':
                case 'smallint':
                case 'mediumint':
                case 'int':
                case 'bigint':
                    $typeName = 'integer';
                    break;
                case 'decimal':
                case 'float':
                case 'double':
                case 'real':
                    $typeName = 'numeric';
                    break;
                default:
                    $typeName = 'string';
            }

            $_columnName = strtoupper($column['COLUMN_NAME']);
            $content .= "\r\n";
            $content .= "         self::C_{$_columnName} => [ \r\n";
            $content .= "             'name' => '{$column['COLUMN_COMMENT']}', \r\n";

            if ($typeName == 'string' && $strLength > 0) {
                $content .= "             'type' => '{$typeName}|max:{$strLength}', \r\n";
            } else {
                $content .= "             'type' => '{$typeName}', \r\n";
            }

            $content .= "             'is_file' => false \r\n";
            $content .= "         ],";
        }

        $content .= "\r\n";
        $content .= "    ];\r\n";
        $content .= "}";

        if(file_exists($file)){
            return;
        }

        file_put_contents($file, $content);
        $modelFile = rtrim($path, '/').'/'.ucfirst($tableName).'Model.php';
        if(file_exists($modelFile)){
            return;
        }

        $content = "<?php \r\n\r\n";
        $content .= "namespace App\Model;\r\n\r\n";
        $content .= "/**\r\n";
        $content .= " * ".$table['Comment']."\r\n";
        $content .= " */\r\n";
        $content .= "class " . $tableName . "Model extends Entity\\{$tableClassName}\r\n{\r\n";
        $content .= '}';

        file_put_contents($modelFile, $content);
    }

    protected function formatDatabaseType(string $type): ?string
    {
        switch ($type) {
            case 'tinyint':
            case 'smallint':
            case 'mediumint':
            case 'int':
            case 'bigint':
                return 'integer';
            case 'decimal':
                // 设置为 decimal，并设置对应精度
                return 'decimal:2';
            case 'float':
            case 'double':
            case 'real':
                return 'float';
            case 'bool':
            case 'boolean':
                return 'boolean';
            default:
                return null;
        }
    }

    protected function formatPropertyType(string $type, ?string $cast): ?string
    {
        if (! isset($cast)) {
            $cast = $this->formatDatabaseType($type) ?? 'string';
        }

        switch ($cast) {
            case 'integer':
                return 'int';
            case 'date':
            case 'datetime':
                return '\Carbon\Carbon';
            case 'json':
                return 'array';
            case 'decimal':
                return 'float';
            default:
                return 'string';
        }

        return $cast;
    }
}
